// #define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#include <dirent.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdarg.h>

#include "config.h"


#ifndef DT_REG
    #define DT_REG 8
#endif


/*
 *自定义strdup()函数，用于兼容不同系统的strdup()函数。
*/
__attribute__((weak)) char *strdup (const char *__s){
    size_t len = strlen(__s) + 1;
    char *new_str = (char *)malloc(len);
    if (new_str == NULL) return NULL;
    strcpy(new_str, __s);
    return new_str;
}

/*
* 自定义strtok_r()函数，用于兼容不同系统的strtok_r()函数。
*/
__attribute__((weak)) char *strtok_r(char *s, const char *delim, char **save_ptr) {  
    char *token;  
  
    if (s == NULL) s = *save_ptr;  
  
    /* Scan leading delimiters.  */  
    s += strspn(s, delim);  
    if (*s == '\0')   
        return NULL;  
  
    /* Find the end of the token.  */  
    token = s;  
    s = strpbrk(token, delim);  
    if (s == NULL)  
        /* This token finishes the string.  */  
        *save_ptr = strchr(token, '\0');  
    else {  
        /* Terminate the token and make *SAVE_PTR point past it.  */  
        *s = '\0';  
        *save_ptr = s + 1;  
    }  
  
    return token;  
}   

/*
 * 去除字符串中空字符
 * @param str 字符串
 * @return 去除空字符后的字符串
 * @note 调用者需要自行free()返回的字符串
*/
void trim(char *str) {
    int i,j;
    for (i = 0, j = 0; str[i]; i++) {
        if (!isspace(str[i])) {
            str[j++] = str[i];
        }
    }
    str[j] = '\0'; 
}

/**
 * @brief 安全的realloc函数，如果realloc失败，则不改变原内存并返回-1
 * @param ptr 指向原内存的指针
 * @param size 新的内存大小
 * @return 成功返回0，失败返回-1
*/
int safe_realloc(void *ptr,size_t size){
    void *new_ptr=realloc(ptr,size);
    if (!new_ptr)
    {
        return -1;
    }
    ptr=new_ptr;    
    return 0;
}

/*
 * 按照delim拆分字符串input
 * @param input 要拆分的字符串
 * @param delim 分隔符
 * @param buf_size 预先分配的buf大小
 * @return 拆分后的字符串数组
 * @note 该函数会自动分配内存，调用者需要自行str_free()返回的字符串数组
*/
char ** str_split(char *input,char *delim,int buf_size){
    char **result=NULL;
    char *saveptr;
    char *token;
    char buf[buf_size];
    strcpy(buf,input);
    if ((token=strtok_r(buf,delim,&saveptr))!=NULL)
    {
        int i=0;
        result=realloc(result,(i+1)*sizeof(char *));
        trim(token);
        result[i]=calloc(strlen(token)+1,1);
        strcpy(result[i],token);
        strcpy(input,token);
        strcat(input,delim);
        while ((token=strtok_r(NULL,delim,&saveptr))!=NULL)
        {   ++i;
            result=realloc(result,(i+1)*sizeof(char *));
            trim(token);
            result[i]=calloc(strlen(token)+1,1);
            strcpy(result[i],token);
            strcat(input,token);
            strcat(input,delim);
        }
        result=realloc(result,(i+2)*sizeof(char *));
        result[i+1]=NULL;
        input[strlen(input)-strlen(delim)]='\0';
    }
    return result;
}

int str_len(char **str){
    if (str==NULL)
        return -1;
    int i=0;
    while (str[i])
    {
        i++;
    }
    return i;
}



/**
 * @brief 安全合并两个字符串（自动内存分配）
 * @param str 第一个字符串（不可为NULL）
 * @param append 要追加的字符串（不可为NULL）
 * @return 新分配的合并字符串指针，失败返回NULL
 * @note 调用者需负责free()返回的指针
 */
char* str_merge(const char *str, const char *append) 
{
    // 参数有效性检查
    if (!str || !append) {
        return NULL;
    }

    // 计算所需空间（包括终止符）
    size_t len1 = strlen(str);
    size_t len2 = strlen(append);
    size_t total_len = len1 + len2 + 1;

    // 分配内存
    char *result = (char*)malloc(total_len);
    if (!result) {
        return NULL;
    }

    // 高效合并
    char *p = result;
    memcpy(p, str, len1);
    p += len1;
    memcpy(p, append, len2 + 1); // 包含'\0'

    return result;
}

/*
 * 释放字符串数组
 * @param str 字符串数组
 * @return 无 
 * @note 该函数会释放字符串数组，并将其指针置为NULL
*/
char * str_merge_n(const char *str,...) {
    va_list ap;
    char *append;
    char *result = NULL;
    int len = 0;

    // 计算总长度
    va_start(ap, str);
    while ((append = va_arg(ap, char*))!= NULL) {
        len += strlen(append);
    }
    va_end(ap);

    // 分配内存
    result = (char*)malloc(len + strlen(str) + 1);
    if (!result) {
        return NULL;
    }

    // 合并字符串
    strcpy(result, str);
    va_start(ap, str);
    while ((append = va_arg(ap, char*))!= NULL) {
        strcat(result, append);
    }
    va_end(ap);

    return result;
}



/*
 * 释放字符串数组
 * @param str 字符串数组
 * @return 无 
 * @note 该函数会释放字符串数组，并将其指针置为NULL
 * @note 该函数会释放字符串数组中的每个字符串
 */
void str_free(char **str){
    if (!str) return;
    for (size_t i=0; str[i]; ++i) {
        free(str[i]);
    }
    free(str);
    str = NULL;
}

/**
 * 规整字符串中的空格
 * 功能：
 * 1. 删除字符串首尾的空格
 * 2. 将连续的多个空格合并为一个空格
 * 3. 原地修改字符串，不分配新内存
 * 
 * @param input 要处理的字符串(会被原地修改)
 */
void str_neat(char *input) {
    if (input == NULL || *input == '\0') return;
    char *dst = input;   // 目标指针
    char *src = input;   // 源指针
    int in_space = 0;    // 标记是否在空格中

    // 跳过前导空格
    while (*src == ' ') {
        src++;
    }

    // 处理字符串中间部分
    while (*src) {
        if (*src == ' ') {
            if (!in_space) {
                *dst++ = ' ';  // 只保留一个空格
                in_space = 1;
            }
            src++;
        } else {
            *dst++ = *src++;   // 复制非空格字符
            in_space = 0;
        }
    }

    // 处理末尾可能多余的空格
    if (dst > input && *(dst-1) == ' ') {
        dst--;
    }

    *dst = '\0';  // 字符串终止
}

void split_dilm(char *light,char *right,const char *str,const char dilm){
    if (str==NULL)
        return;
    char *last_slash=strrchr(str,dilm);
    if (last_slash==NULL&&right!=NULL)
    {
        strcpy(right,str);
        return;
    }
    if (light!=NULL)
    {
        strncpy(light,str,last_slash-str);
        light[last_slash-str]='\0';
    }
    if (right!=NULL)
    {
        strcpy(right,++last_slash);
    }
    return;
}

//拆分文件和路径
void split_dir_file(char *dir,char *file,const char *filepath){
    split_dilm(dir,file,filepath,'/');
}

/*
 * 判断某个字符串是否拥有指定后缀成功返回1否则返回0 
 * @param str 字符串
 * @param suffix 后缀字符串
 * @return 1表示成功，0表示失败
 * @note 该函数不对输入参数做任何检查，如果参数为空则返回0
 */ 
int str_has_suffix(const char *str, const char *suffix) {
    int n, m, i = 0;
    // char ch = '\0';
    if (str == NULL || suffix == NULL)
    {
        return 0;
    }
    n = strlen(str);
    m = strlen(suffix);
    if (n < m) {
        return 0;
    }
    for (i = m-1; i >= 0;  i--) {
        if (suffix[i] != str[n - m + i]) {
            return 0;
        }
    }
    return 1;   
}


/*
 * 解析ini文件
 * @param user 自定义的结构体指针
 * @param path ini文件路径
 * @param handler 处理函数
 * @param mtime 文件最后修改时间指针
 * @return 成功返回0，失败返回-1
 * @note 该函数不对输入参数做任何检查，如果参数为空则返回-1
 * @note 该函数会自动去除ini文件中空格
 * @note 该函数会自动去除ini文件中注释
 * @note 该函数会自动去除ini文件中section和key中的空格
 * @note 该函数会自动去除ini文件中value中的空格
 * @note 该函数会自动调用handler函数处理ini文件中的key-value对
 * @note 该函数会自动更新mtime指针
 * @note 该函数会自动释放内存
 * @note 该函数会自动处理ini文件中的section
*/
int ini_parse(void* user,const char *path,ini_handler handler,long *mtime){
    //记录文件最后修改时间
    struct stat filestat;
    stat(path,&filestat);
    if (mtime!=NULL)
    {
        *mtime=(long)filestat.st_mtime;
    }
    //解析文件
    FILE *file = fopen(path, "r");
    if (file == NULL) {
        // debug("Error: %s opening file\n",path);
        fprintf(stderr, "Error: Cannot open file %s (%s)\n", path, strerror(errno));
        return -1;
    }

    char dir[4096];
    char filename[4096];
    split_dir_file(dir,filename,path);
    char line[4096];
    char section[4096] = "";
    char key_str[4096];
    char value_str[4096];
    while (fgets(line, sizeof(line), file)) {
        // 处理行过长情况
        if (strlen(line) == sizeof(line) - 1 && line[sizeof(line) - 2] != '\n') {
            fprintf(stderr, "Warning: Truncated long line in %s\n", path);
            continue;
        }
        // 跳过空行和注释行
        if (line[0] == '\0' || line[0] == ';' || line[0] == '#') {
            continue;  
        }

        line[strlen(line)]='\0';
        if (strchr(line,'[')&&strchr(line,']')) {
            trim(line);
            strncpy(section, line + 1, strlen(line) - 2);
            section[strlen(line) - 2] = '\0';
        } else if (strchr(line, '=')) {
            char *saveptr;
            char *key = strtok_r(line, "=",&saveptr);
            char *value = strtok_r(NULL, "\0",&saveptr);
            trim(key);
            strcpy(key_str,key);
            strcpy(value_str,value);
            handler(user,section,key_str,value_str);
        }
    }
    fclose(file);
    return 0;
}

/**
 * 解析INI配置文件
 * @param user 用户数据指针，会传递给handler回调
 * @param path INI文件路径
 * @param handler 处理每个键值对的回调函数
 * @param mtime 可选参数，用于返回文件最后修改时间
 * @return 成功返回0，失败返回负的错误码
 */
int ini_mmap_parse(void *user, const char *path, ini_handler handler, long *mtime) {
    // 参数检查
    if (!path || !handler) {
        errno = EINVAL;
        return -EINVAL;
    }

    // 打开文件并获取文件信息
    int fd = open(path, O_RDONLY);
    if (fd == -1) {
        return -errno;
    }

    struct stat filestat;
    if (fstat(fd, &filestat) == -1) {
        int saved_errno = errno;
        close(fd);
        return -saved_errno;
    }

    // 设置修改时间
    if (mtime) {
        
        *mtime =(long) filestat.st_mtime;
        printf("mtime: %ld\n",filestat.st_mtime);
    }

    // 空文件直接返回
    if (filestat.st_size == 0) {
        close(fd);
        return 0;
    }

    // 内存映射文件
    char *mapped = mmap(NULL, filestat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    if (mapped == MAP_FAILED) {
        int saved_errno = errno;
        close(fd);
        return -saved_errno;
    }

    // 解析状态
    char current_section[256] = "";
    const char *ptr = mapped;
    const char *end = mapped + filestat.st_size;
    int ret = 0;

    while (ptr < end && ret == 0) {
        // 跳过前导空白
        while (ptr < end && isspace((unsigned char)*ptr)) {
            ptr++;
        }

        // 处理行结束
        const char *line_start = ptr;
        while (ptr < end && *ptr != '\n' && *ptr != '\r') {
            ptr++;
        }

        // 计算行长度
        size_t line_len = ptr - line_start;

        // 跳过空行和注释
        if (line_len == 0 || *line_start == ';' || *line_start == '#') {
            goto next_line;
        }

        // 解析section [section]
        if (*line_start == '[') {
            const char *section_end = memchr(line_start, ']', line_len);
            if (section_end && section_end > line_start + 1) {
                size_t sect_len = section_end - line_start - 1;
                strncpy(current_section, line_start + 1, sect_len);
                current_section[sect_len] = '\0';
            }
            goto next_line;
        }

        // 解析键值对 key=value
        const char *equals = memchr(line_start, '=', line_len);
        if (equals && equals > line_start && equals < line_start + line_len - 1) {
            // 提取key
            const char *key_end = equals;
            while (key_end > line_start && isspace((unsigned char)*(key_end - 1))) {
                key_end--;
            }
            
            // 提取value
            const char *value_start = equals + 1;
            while (value_start < line_start + line_len && isspace((unsigned char)*value_start)) {
                value_start++;
            }
            
            const char *value_end = line_start + line_len;
            while (value_end > value_start && isspace((unsigned char)*(value_end - 1))) {
                value_end--;
            }

            // 复制key和value
            char key[256], value[1024];
            size_t key_len = key_end - line_start;
            size_t value_len = value_end - value_start;

            if (key_len >= sizeof(key) || value_len >= sizeof(value)) {
                ret = -ENAMETOOLONG;
                break;
            }

            memcpy(key, line_start, key_len);
            key[key_len] = '\0';
            memcpy(value, value_start, value_len);
            value[value_len] = '\0';

            // 调用回调函数
            handler(user, current_section, key, value);
        }

    next_line:
        // 跳过换行符
        while (ptr < end && (*ptr == '\n' || *ptr == '\r')) {
            ptr++;
        }
    }

    // 清理资源
    if (munmap(mapped, filestat.st_size) == -1) {
        ret = -errno;
    }
    close(fd);

    return ret;
}


/*
 * 加载目录中的文件
 * @param path 目录路径
 * @param suffix 后缀字符串
 * @return 成功返回文件路径字符串数组，失败返回NULL
 * @note 该函数不会自动释放内存，需要调用str_free()释放
*/
char ** load_dir(const char *path,const char *suffix){
    char** files=NULL;
    DIR *dir=opendir(path);
    if (dir != NULL)
    {
        struct dirent *entry;
        int i=0;
        while ((entry=readdir(dir)) != NULL)
        {   
            if (entry->d_type == 8)
            {
                if ( str_has_suffix((char*)entry->d_name,suffix) == 1)
                {
                    files=realloc(files,(i+2)*sizeof(char*));
                    files[i]=malloc((strlen(entry->d_name)+1)*sizeof(char));
                    strcpy(files[i],entry->d_name);
                    i++;
                }
            } 
        }
        if (i>0)
        {
            files[i]=NULL;
        }
        closedir(dir); 

    }else{
        printf("open %s dir error:%s\n",path,strerror(errno));
        return NULL;
    }
    return files;
}

/*
 * 遍历目录
 * @param dirname 目录路径
 * @param suffix 后缀字符串
 * @return 成功返回文件路径字符串数组，失败返回NULL
 * @note 该函数不会自动释放内存，需要调用str_free()释放
*/
char ** listFiles_fromDir_suffix(const char *dirname,const char *suffix){
    char** files=NULL;
    DIR *dir=opendir(dirname);
    if (dir != NULL)
    {
        struct dirent *entry;
        int i=0;
        while ((entry=readdir(dir)) != NULL)
        {   
            if (entry->d_type == 8)
            {
                if ( str_has_suffix((char*)entry->d_name,suffix) == 1)
                {
                    files=realloc(files,(i+2)*sizeof(char*));
                    files[i]=str_merge_n(entry->d_name,NULL);
                    i++;
                }
            } 
        }
        if (i>0)
        {
            files[i]=NULL;
        }
        closedir(dir); 

    }else{
        printf("open %s dir error:%s\n",dirname,strerror(errno));
        return NULL;
    }
    return files;
}

/*
 * 遍历目录
 * @param dir 目录路径
 * @param multi_suffix 多后缀字符串，以 | 分割
 * @return 成功返回文件路径字符串数组，失败返回NULL
 * @note 该函数不会自动释放内存，需要调用str_free()释放
 */
char ** listFilesPath_fromDir_multiSuffix(const char *dir,const char *multi_suffix){ 
    if (!dir ||!multi_suffix) return NULL;
    char **filesPath=NULL;
    DIR *dirptr;
    struct dirent *entry;
    if ((dirptr = opendir(dir)) == NULL) {
        fprintf(stderr, "Error: Cannot open directory %s (%s)\n", dir, strerror(errno));
        return NULL;
    }
    char * suffix=strdup(multi_suffix);
    trim(suffix);
    char **suffix_arr=str_split(suffix,"|",4096);
    int i=0;
    while ((entry = readdir(dirptr)     ) != NULL)
    {       
            if (entry->d_type == DT_REG) {
                int j=0;
                while (suffix_arr[j]!=NULL)
                {
                    if (str_has_suffix(entry->d_name,suffix_arr[j])==1)
                    {
                        filesPath=realloc(filesPath,(i+2)*sizeof(char*));
                        if (dir[strlen(dir)-1]=='/')
                        {
                            filesPath[i]=str_merge_n(dir,entry->d_name,NULL);
                        }else{
                            filesPath[i]=str_merge_n(dir,"/",entry->d_name,NULL);
                        }
                        i++;
                        break;
                    }
                    j++;
                }
            }
    }
    if (i>0) filesPath[i]=NULL;
    closedir(dirptr);
    free(suffix);
    return filesPath;
}

// 从字符串字面值或者字符串数组中,创建string字符串
string string_from(char *str){
    string s;
    s.str=str;
    s.len=strlen(str);
    s.cap=s.len+1;
    return s;
}

// 
string string_clone(const string s){
    string new_s;
    new_s.str=calloc(s.cap,sizeof(char));
    strncpy(new_s.str,s.str,s.len);  
    new_s.len=s.len;
    new_s.cap=s.cap;
    return new_s;   
}

// 清除string字符串
void string_clean(string *s){
    if (s->str!=NULL)
    {
        free(s->str);
    }
    s->str=NULL;
    s->len=0;
    s->cap=0;
}
  

// 向string字符串追加string字符串
string string_append(string s,.../*string String,*/){
    va_list args;
    va_start(args, s);
    string String=va_arg(args,string);
    va_end(args);
    s.str=realloc(s.str,s.len+String.len+1);
    strcpy(s.str+s.len,String.str);
    s.len+=String.len;
    s.cap=s.len+1;
    return s;
}

// 向string字符串追加字符串
string string_append_str(string s,const char *str){
    s.str=realloc(s.str,s.len+strlen(str)+1);
    strcpy(s.str+s.len,str);
    s.len+=strlen(str);
    s.cap=s.len+1;
    return s;
}

/*
 * string字符串分割
 * @param s 待分割的字符串
 * @param dilm 分隔符
 * @return 成功返回字符串数组，失败返回NULL
 * @note 该函数不会自动释放内存，需要调用string_free()释放
*/ 
string * string_split(const string s, const string dilm){
    string *array=NULL;
    string strclone=string_clone(s);
    char *saveptr=NULL;
    char *token=strtok_r(strclone.str,dilm.str,&saveptr);
    while (token!=NULL)
    {
        int i=0;
        array=realloc(array,(i+1)*sizeof(string));
        array[i].str=token;
        array[i].len=strlen(token);
        array[i].cap=array[i].len+1;
        i++;
        token=strtok_r(NULL,dilm.str,&saveptr);
    }
    string_clean(&strclone);
    return array;
}

// 释放string字符串数组
void string_free(string *s){    
        if (s!=NULL)
        {
            for (int i=0;s[i].str!=NULL;i++)
            {
                string_clean(&s[i]);        
            }
            free(s);
        }
}

